package hotciv.variant;

import hotciv.framework.*;
import hotciv.standard.*;
import java.awt.Color;
import hotciv.exceptions.*;

public class DeltaCivMoveUnitStrategy implements MoveUnitStrategy {

	public boolean moveUnit(GameTesting g, Position from, Position to) {

		//g.getWinner();

			/** check preconditions */
			g.isWithinWorldLimit(from);
			g.isWithinWorldLimit(to);
			Tile destination = g.getTile(to);
			Tile departure = g.getTile(from);
			Unit unitAtDest = g.getUnitAt(to);
			Unit unitToMove = g.getUnitAt(from);
			if(unitToMove == null) return false; //throw new MoveErrorException("No unit at "+from+"!");
			if(destination.getTypeString() == GameConstants.MOUNTAINS) return false; //
				//throw new MoveErrorException("Cannot move over mountains!");
			if(destination.getTypeString() == GameConstants.OCEANS)
				return false; //throw new MoveErrorException("Cannot move thrugh water!");
			if(unitToMove.getOwner() != g.getPlayerInTurn()) 
				return false; //throw new MoveErrorException(g.getPlayerInTurn()+" cannot move "+unitToMove.getOwner()+"'s units");
			if(unitToMove.getMoveCount() < 1) return false; //throw new MoveErrorException("MoveCount reached 0!");
			if(from.equals(to)) return false; //throw new MoveErrorException("Can't move to same location");
			if(unitAtDest != null && unitAtDest == g.getPlayerInTurn())
				return false; //throw new MoveErrorException(unitToMove.getOwner()+"'s unit already at "+to);	

			/** move the unit here */
			unitToMove.decrementMoveCount();
			departure.removeTopUnit();
			if(Math.abs(from.getColumn()-to.getColumn()) > 1) return false;
			System.out.println("Move from "+from+" to "+to);
			//if enemy unit there
			if(unitAtDest != null && unitAtDest.getOwner() != g.getPlayerInTurn()) {
				//Battle! 
				if( this.battle(g, unitToMove, unitAtDest, from, to) ) {
					//attacking unit wins
					destination.removeTopUnit();
					System.out.println("1 "+unitAtDest.getOwner()+" down, "+unitToMove.getOwner()+" has "+(2-g.getPlayerInTurn().getWonAttacks())+" to go");
					System.out.println(unitToMove.getOwner()+" won the battle attacking "+to);
					g.getPlayerInTurn().incrementWonAttackts();
					destination.addUnit(unitToMove);
					//this.moveUnit(g, from, to); //recurcive call, if more that one unit is allowed per Tile.	
				} else {
					System.out.println(unitAtDest.getOwner()+" won the battle defending "+to);
					//defending unit wins
					departure.removeTopUnit();
					unitAtDest.getOwner().incrementWonAttackts();
				}
			} else {
				System.out.println(unitToMove.getMoveCount());
				System.out.println("No units at "+to+" - moving...");
				destination.addUnit(unitToMove);
				
				g.endOfTurn();
				System.out.println(unitToMove.getMoveCount());
			}

			//if enemy city there
			CityTesting cityInTheWay = (CityTesting)g.getCityAt(to);
			if(cityInTheWay != null && cityInTheWay.getOwner() != g.getPlayerInTurn()) {
				System.out.println("Un-protected enemy city at "+to+" - taking over!");
				//int residents = cityInTheWay.getSize();
				//System.out.println(to+" - "+inTurn+" found enemy CITY... takeing over "+cityInTheWay.getOwner()+" city");
				//destination.getCityList().remove(cityInTheWay);
				//destination.addCity(new StandardCity(inTurn,residents));
				cityInTheWay.setOwner(g.getPlayerInTurn());

			}
			//if(this.getWinner() != null)
			//	System.out.println(this.getWinner()+" is the winner!");

		return true;
	}


	private boolean battle(GameTesting g, Unit f, Unit t, Position from, Position to) {
		System.out.println("battles units");
		int unitAttack = f.getAttackingStrength();
		int unitDefend = t.getDefensiveStrength();
		int adjcAttack = countAdjcUnits(g, from, f.getOwner().getColor());
		int adjcDefend = countAdjcUnits(g, to, t.getOwner().getColor());
		int diceOne = (int)(Math.round(Math.random()*6));
		int diceTwo = (int)(Math.round(Math.random()*6));
		int playerOne = ((unitAttack+adjcAttack)*fromGround(g,from))*diceOne;
		int playerTwo = ((unitDefend+adjcDefend)*fromGround(g,to))*diceTwo;
		//System.out.println("p1: (("+unitAttack+"+"+adjcAttack+")*("+(adjcAttack+1)+"))*"+diceOne+" = "+playerOne);
		//System.out.println("p2: (("+unitDefend+"+"+adjcDefend+")*("+(adjcDefend+1)+"))*"+diceTwo+" = "+playerTwo);

		System.out.println(playerOne +" > "+playerTwo+" (playerOne > playerTwo)");
		return playerOne > playerTwo;
	}

	/**
	 * Returns the strength multiplier given by the tile at position p
	 * @param g Game instance.
	 * @param p Position of the callee.
	 * @return strength multiplier given by the type of the tile.
	 */
	private int fromGround(Game g, Position p) {
		int multilplier = 1;

		if(g.getTile(p).getTypeString().equals("forest") ||
				g.getTile(p).getTypeString().equals("hill")) {
			multilplier = 2;
		}
		if(!(g.getTile(p).getCityList().isEmpty())) {
			multilplier = 3;
		}

		return multilplier;
	}

	/**
	 * Returns the strength multiplier added to the unit, due to adjcent
	 * units. That is, units on Tiles surrunding the 'tile'
	 * @param g The Game instance
	 * @param tile the position of the unit
	 * @param c the color of the unit
	 * @return strength multiplier added to the unit
	 */
	private int countAdjcUnits(GameTesting g, Position tile, Color c) {
		int strength = 0;
		for(int x=-1;x<=1;x++) {
			for(int y=-1;y<=1;y++) {
				Position p = new Position((tile.getColumn()+(x)),(tile.getRow()+(y)));
				if(!(p.equals(tile))) {
					//System.out.println(tile);
					//System.out.println(p+"\n");
					if(g.isWithinWorldLimit(p)) {
						if(g.getUnitAt(p) != null) {
							if(g.getUnitAt(p).getOwner().getColor() == c) {
								strength++;
							}
						}
					}
				}
			}
		}
		return strength;
	}






}